#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
SQL自动补全模块
为SQL编辑器提供智能补全功能
"""

import re
import logging
from typing import List, Dict, Any, Optional, Tuple
import time

from PySide6.QtCore import Qt, QObject, Signal, QPoint, QTimer, QSize, QEvent
from PySide6.QtWidgets import (QListWidget, QListWidgetItem, QWidget,
                              QVBoxLayout, QLabel, QFrame, QPlainTextEdit,
                              QAbstractItemView, QScrollBar, QHBoxLayout)
from PySide6.QtGui import QFont, QColor, QTextCursor, QIcon, QPixmap, QGuiApplication, QPainter, QPainterPath

from config.constants import SQL_KEYWORDS
from core.db_engine import get_db_engine


# 初始化日志记录器
logger = logging.getLogger("completion")


class CompletionItem:
    """补全项类，表示一个自动补全选项"""
    
    TYPE_KEYWORD = "keyword"     # 关键字
    TYPE_TABLE = "table"         # 表
    TYPE_COLUMN = "column"       # 列
    TYPE_FUNCTION = "function"   # 函数
    TYPE_OPERATOR = "operator"   # 操作符
    TYPE_ALIAS = "alias"         # 别名
    TYPE_SNIPPET = "snippet"     # 代码片段
    
    def __init__(self, text: str, type_: str, description: Optional[str] = None, 
                priority: int = 0, detail: Optional[str] = None,
                insert_text: Optional[str] = None):
        """初始化补全项
        
        Args:
            text: 补全文本
            type_: 补全类型
            description: 描述文本
            priority: 优先级（数字越大优先级越高）
            detail: 详细信息
            insert_text: 插入文本（如果与显示文本不同）
        """
        self.text = text
        self.type = type_
        self.description = description or ""
        self.priority = priority
        self.detail = detail or ""
        self.insert_text = insert_text or text


class CompletionItemWidget(QWidget):
    """自定义补全项显示部件"""
    
    def __init__(self, item: CompletionItem, parent=None):
        """初始化补全项部件
        
        Args:
            item: 补全项
            parent: 父部件
        """
        super().__init__(parent)
        
        # 设置对象名和CSS类
        self.setObjectName("CompletionItemWidget")
        
        # 创建布局
        layout = QHBoxLayout(self)
        layout.setContentsMargins(8, 4, 8, 4)
        layout.setSpacing(10)
        
        # 图标标签
        icon_label = QLabel()
        icon_label.setFixedSize(16, 16)
        
        # 根据类型设置图标、文本和CSS类
        if item.type == CompletionItem.TYPE_KEYWORD:
            icon_label.setText("K")
            icon_label.setAlignment(Qt.AlignCenter)
            icon_label.setProperty("class", "completion-icon-keyword")
        elif item.type == CompletionItem.TYPE_TABLE:
            icon_label.setText("T")
            icon_label.setAlignment(Qt.AlignCenter)
            icon_label.setProperty("class", "completion-icon-table")
        elif item.type == CompletionItem.TYPE_COLUMN:
            icon_label.setText("C")
            icon_label.setAlignment(Qt.AlignCenter)
            icon_label.setProperty("class", "completion-icon-column")
        elif item.type == CompletionItem.TYPE_FUNCTION:
            icon_label.setText("F")
            icon_label.setAlignment(Qt.AlignCenter)
            icon_label.setProperty("class", "completion-icon-function")
        elif item.type == CompletionItem.TYPE_OPERATOR:
            icon_label.setText("O")
            icon_label.setAlignment(Qt.AlignCenter)
            icon_label.setProperty("class", "completion-icon-operator")
        elif item.type == CompletionItem.TYPE_ALIAS:
            icon_label.setText("A")
            icon_label.setAlignment(Qt.AlignCenter)
            icon_label.setProperty("class", "completion-icon-alias")
        elif item.type == CompletionItem.TYPE_SNIPPET:
            icon_label.setText("S")
            icon_label.setAlignment(Qt.AlignCenter)
            icon_label.setProperty("class", "completion-icon-snippet")
            
        layout.addWidget(icon_label)
        
        # 内容容器 (垂直布局显示文本和描述)
        content_widget = QWidget()
        content_layout = QVBoxLayout(content_widget)
        content_layout.setContentsMargins(0, 0, 0, 0)
        content_layout.setSpacing(0)
        
        # 文本标签
        text_label = QLabel(item.text)
        text_label.setFont(QFont("Segoe UI", 10))
        
        # 根据类型设置文本CSS类
        if item.type == CompletionItem.TYPE_KEYWORD:
            text_label.setProperty("class", "completion-text-keyword")
            text_label.setText(item.text.upper())  # 关键字总是显示为大写
        elif item.type == CompletionItem.TYPE_TABLE:
            text_label.setProperty("class", "completion-text-table")
        elif item.type == CompletionItem.TYPE_COLUMN:
            text_label.setProperty("class", "completion-text-column")
        elif item.type == CompletionItem.TYPE_FUNCTION:
            text_label.setProperty("class", "completion-text-function")
        elif item.type == CompletionItem.TYPE_ALIAS:
            text_label.setProperty("class", "completion-text-alias")
            
        content_layout.addWidget(text_label)
        
        # 描述标签 (如果有)
        if item.description:
            desc_label = QLabel(item.description)
            desc_label.setFont(QFont("Segoe UI", 8))
            desc_label.setProperty("class", "completion-desc")
            content_layout.addWidget(desc_label)
            
        layout.addWidget(content_widget, 1)  # 1表示拉伸因子
        
        # 详情（如果有）- 右侧显示
        if item.detail:
            detail_label = QLabel(item.detail)
            detail_label.setFont(QFont("Segoe UI", 8))
            detail_label.setProperty("class", "completion-detail")
            layout.addWidget(detail_label, 0)
            
        self.setLayout(layout)
        
        # 设置固定高度 - 根据是否有描述调整高度
        self.setFixedHeight(item.description and 42 or 28)


class CompletionPopup(QFrame):
    """自定义补全弹出窗口"""
    
    item_selected = Signal(str)  # 选中的补全项文本
    
    def __init__(self, parent=None):
        """初始化补全弹出窗口
        
        Args:
            parent: 父窗口
        """
        super().__init__(parent)
        
        # 检测操作系统
        import platform
        self.is_macos = platform.system() == 'Darwin'
        
        # 设置对象名
        self.setObjectName("CompletionPopup")
        
        # 设置窗口属性 - macOS 和其他平台使用不同的标志
        if self.is_macos:
            # macOS 使用工具窗口标志，避免闪退问题
            self.setWindowFlags(Qt.ToolTip | Qt.FramelessWindowHint)
            # macOS 使用透明背景配合自定义绘制
            self.setAttribute(Qt.WA_TranslucentBackground)
        else:
            # 其他平台使用原来的标志
            self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint)
            
        self.setAttribute(Qt.WA_ShowWithoutActivating)
        self.setFrameShape(QFrame.StyledPanel)
        
        # 设置无焦点策略使得点击外部区域自动隐藏
        self.setFocusPolicy(Qt.NoFocus)
        
        # 移除内联样式，让QSS样式表接管
        self.setStyleSheet("")
        
        # 创建布局
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 2, 0, 2)
        layout.setSpacing(0)
        
        # 创建标题部分
        self.header = QLabel("SQL 补全")
        # 移除内联样式，让QSS接管
        self.header.setStyleSheet("")
        layout.addWidget(self.header)
        
        # 创建列表控件
        self.list_widget = QListWidget(self)
        self.list_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.list_widget.setSelectionMode(QAbstractItemView.SingleSelection)
        self.list_widget.itemClicked.connect(self._handle_item_clicked)
        self.list_widget.setMouseTracking(True)  # 使鼠标悬停可高亮项目
        
        # 设置列表控件的圆角样式，确保不覆盖父控件的圆角
        self.list_widget.setStyleSheet("""
            QListWidget {
                background-color: transparent;
                border: none;
                border-radius: 4px;
                outline: none;
            }
            QListWidget::item {
                background-color: transparent;
                border: none;
                padding: 0px;
                margin: 1px 0px;
                border-radius: 4px;
            }
            QListWidget::item:selected {
                background-color: rgba(227, 242, 253, 180);
                color: #1976d2;
            }
            QListWidget::item:hover {
                background-color: rgba(245, 245, 245, 120);
            }
        """)
        
        layout.addWidget(self.list_widget)
        self.setLayout(layout)
        
        # 设置大小
        self.setMinimumWidth(320)
        self.setMaximumHeight(400)
        self.setMaximumWidth(500)
        
        # 存储当前补全项
        self.current_items = []
        
        # 支持鼠标悬停选择
        self.list_widget.itemEntered.connect(self._handle_item_hovered)
        
    def _handle_item_clicked(self, item):
        """处理项目点击
        
        Args:
            item: 点击的列表项
        """
        row = self.list_widget.row(item)
        if 0 <= row < len(self.current_items):
            completion_item = self.current_items[row]
            self.item_selected.emit(completion_item.insert_text)
            self.hide()
            
    def _handle_item_hovered(self, item):
        """处理项目悬停
        
        Args:
            item: 悬停的列表项
        """
        # 设置当前行，但不触发选择
        self.list_widget.setCurrentItem(item)
        
    def set_items(self, items: List[CompletionItem]):
        """设置补全项列表
        
        Args:
            items: 补全项列表
        """
        self.list_widget.clear()
        
        # 保存当前项目
        self.current_items = items
        
        # 根据上下文决定标题内容
        if len(items) > 0:
            type_counts = {}
            for item in items:
                type_counts[item.type] = type_counts.get(item.type, 0) + 1
            
            type_names = {
                CompletionItem.TYPE_KEYWORD: "关键字",
                CompletionItem.TYPE_TABLE: "表",
                CompletionItem.TYPE_COLUMN: "列",
                CompletionItem.TYPE_FUNCTION: "函数",
                CompletionItem.TYPE_OPERATOR: "操作符",
                CompletionItem.TYPE_ALIAS: "别名"
            }
            
            header_text = "SQL 补全: " + ", ".join([f"{type_names.get(t, t)}({c})" for t, c in type_counts.items()])
            self.header.setText(header_text)
        else:
            self.header.setText("SQL 补全")
        
        # 按优先级排序，优先处理关键字
        sorted_items = sorted(items, key=lambda x: (
            # 首先按类型排序，关键字优先
            0 if x.type == CompletionItem.TYPE_KEYWORD else 1,
            # 然后按优先级降序排序
            -x.priority,
            # 最后按文本排序
            x.text.lower()
        ))
        
        for item in sorted_items:
            list_item = QListWidgetItem(self.list_widget)
            
            # 创建自定义部件
            item_widget = CompletionItemWidget(item)
            
            # 设置项目大小
            list_item.setSizeHint(item_widget.sizeHint())
            
            # 设置自定义部件
            self.list_widget.addItem(list_item)
            self.list_widget.setItemWidget(list_item, item_widget)
            
        # 如果有项目，选择第一个
        if self.list_widget.count() > 0:
            self.list_widget.setCurrentRow(0)
            
        # 调整大小
        items_count = min(12, self.list_widget.count())
        if items_count > 0:
            # 根据项目高度计算总高度
            total_height = 0
            for i in range(min(items_count, len(sorted_items))):
                item_widget = self.list_widget.itemWidget(self.list_widget.item(i))
                total_height += item_widget.height() + 2  # 2px for padding
                
            # 添加标题高度
                total_height += self.header.height()
                
            # 添加额外的边距
            total_height += 10
            
            self.setFixedHeight(min(total_height, 400))
        else:
            self.setFixedHeight(0)
        
    def move_selection(self, direction: int):
        """移动选择
        
        Args:
            direction: 方向 (1 = 下, -1 = 上)
        """
        current_row = self.list_widget.currentRow()
        item_count = self.list_widget.count()
        
        if item_count == 0:
            return
            
        new_row = (current_row + direction) % item_count
        self.list_widget.setCurrentRow(new_row)
        self.list_widget.scrollToItem(self.list_widget.currentItem())
        
    def select_current(self) -> Optional[str]:
        """选择当前项
        
        Returns:
            选择的插入文本或None
        """
        current_row = self.list_widget.currentRow()
        if 0 <= current_row < len(self.current_items):
            return self.current_items[current_row].insert_text
        return None

    def show(self):
        """显示补全窗口"""
        # 在 macOS 上，确保窗口位于顶层
        if hasattr(self, 'is_macos') and self.is_macos:
            self.setParent(None)  # 移除父窗口关系
            self.setWindowFlags(Qt.ToolTip | Qt.FramelessWindowHint)
            
        # 确保窗口显示在最前面
        super().show()
        self.raise_()
        
    def hideEvent(self, event):
        """隐藏事件处理
        
        Args:
            event: 事件
        """
        # 在隐藏补全框时执行的操作
        super().hideEvent(event)
        
        # 通知其他组件窗口已隐藏
        # 查找父级 SQLCompleter
        parent = self.parent()
        while parent:
            if hasattr(parent, 'popup_visible') and isinstance(parent, SQLCompleter):
                parent.popup_visible = False
                break
            parent = parent.parent()

    def paintEvent(self, event):
        """自定义绘制事件 - 绘制圆角背景"""
        painter = QPainter(self)
        # 设置高质量抗锯齿
        painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
        painter.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform, True)
        painter.setRenderHint(QPainter.RenderHint.TextAntialiasing, True)
        
        # 创建圆角矩形路径
        path = QPainterPath()
        rect = self.rect()
        border_radius = 8.0  # 使用浮点数，更精确
        # 调整矩形大小，为边框留出空间
        adjusted_rect = rect.adjusted(0.25, 0.25, -0.25, -0.25)
        path.addRoundedRect(adjusted_rect, border_radius, border_radius)
        
        # 根据系统风格设置不同的背景色和边框
        if hasattr(self, 'is_macos') and self.is_macos:
            # macOS风格：白色背景，浅灰色边框
            painter.fillPath(path, QColor(255, 255, 255, 250))  # 略微透明的白色
            # 使用更细的边框，减少锯齿感
            pen = painter.pen()
            pen.setColor(QColor(192, 192, 192))
            pen.setWidthF(0.5)  # 使用浮点数宽度，更平滑
            painter.setPen(pen)
        else:
            # Windows/Linux风格：白色背景（与macOS保持一致）
            painter.fillPath(path, QColor(255, 255, 255, 250))  # 白色背景
            # 使用更细的边框，减少锯齿感
            pen = painter.pen()
            pen.setColor(QColor(192, 192, 192))
            pen.setWidthF(0.5)  # 使用浮点数宽度，更平滑
            painter.setPen(pen)
        
        painter.drawPath(path)
        
        # 设置窗口遮罩，确保整个窗口都是圆角
        from PySide6.QtGui import QRegion
        region = QRegion(path.toFillPolygon().toPolygon())
        self.setMask(region)
        
        # 如果有标题，绘制标题区域的分隔线
        if hasattr(self, 'header') and self.header.isVisible():
            header_height = self.header.height()
            # 绘制标题下方的分隔线
            line_y = header_height + 4  # 4px是layout的上边距
            
            # 分隔线也使用抗锯齿
            pen = painter.pen()
            pen.setColor(QColor(224, 224, 224))
            pen.setWidthF(0.5)
            painter.setPen(pen)
            painter.drawLine(8, line_y, self.width() - 8, line_y)
        
        # 不调用父类的paintEvent，避免默认绘制干扰


class SQLCompleter(QObject):
    """SQL自动补全器，提供智能SQL补全功能"""
    
    # 限制返回的补全项数量，避免卡顿
    MAX_ITEMS = 50
    
    def __init__(self, editor):
        """初始化SQL补全器
        
        Args:
            editor: SQL编辑器组件
        """
        super().__init__(editor)
        self.editor = editor
        
        # 检测操作系统
        import platform
        self.is_macos = platform.system() == 'Darwin'
        
        # 创建补全弹出窗口
        self.popup = CompletionPopup()
        self.popup.item_selected.connect(self._insert_completion)
        
        # 加载SQL关键字和函数
        self.all_keywords = []
        self.all_functions = []
        self.duckdb_functions = []
        self.column_type_mappings = {}  # 列名 -> 数据类型
        self.table_columns = {}  # 表名 -> 列列表
        self.table_aliases = {}  # 别名 -> 表名
        self.recent_completions = []  # 最近使用的补全项
        self.last_update_time = 0  # 上次更新元数据的时间
        self.current_items = []  # 当前补全项列表
        
        # macOS 上的补全窗口可能不稳定，跟踪窗口显示状态
        self.popup_show_attempts = 0
        self.popup_visible = False
        self.last_popup_time = 0
        
        # 检查全局设置
        from config.settings import settings
        self.use_fallback_completion = self.is_macos and settings.get("use_fallback_completion", False)
        
        # 初始化代码片段
        self.sql_snippets = {
            "sel": CompletionItem(
                "SELECT * FROM", 
                CompletionItem.TYPE_SNIPPET,
                "基本SELECT查询",
                100,
                "选择所有列",
                "SELECT * FROM "
            ),
            "selc": CompletionItem(
                "SELECT COUNT(*) FROM", 
                CompletionItem.TYPE_SNIPPET,
                "计数查询",
                100,
                "计算行数",
                "SELECT COUNT(*) FROM "
            ),
            "selw": CompletionItem(
                "SELECT * FROM ... WHERE", 
                CompletionItem.TYPE_SNIPPET,
                "带WHERE条件的查询",
                100,
                "筛选数据",
                "SELECT * FROM  WHERE "
            ),
            "selg": CompletionItem(
                "SELECT ..., COUNT(*) FROM ... GROUP BY", 
                CompletionItem.TYPE_SNIPPET,
                "分组查询",
                100,
                "分组统计",
                "SELECT , COUNT(*) FROM  GROUP BY "
            ),
            "join": CompletionItem(
                "SELECT * FROM t1 JOIN t2 ON t1.id = t2.id", 
                CompletionItem.TYPE_SNIPPET,
                "JOIN查询",
                100,
                "表连接",
                "SELECT * FROM  JOIN  ON . = ."
            ),
            "ctas": CompletionItem(
                "CREATE TABLE ... AS SELECT", 
                CompletionItem.TYPE_SNIPPET,
                "创建表并填充数据",
                100,
                "表创建",
                "CREATE TABLE  AS SELECT "
            ),
        }
        
        # 初始化关键字和函数
        self._init_keywords_and_functions()
        
        # 定时更新元数据
        self.metadata_timer = QTimer(self)
        self.metadata_timer.timeout.connect(self.update_metadata)
        self.metadata_timer.start(60000)  # 每分钟更新一次
        
        # 立即更新元数据
        QTimer.singleShot(500, self.update_metadata)
        
        # 连接编辑器信号
        self._connect_editor_signals()
        
    def _init_keywords_and_functions(self):
        """初始化SQL关键字和函数列表"""
        # SQL关键字
        keywords = [
            'SELECT', 'FROM', 'WHERE', 'AND', 'OR', 'NOT', 'ORDER', 'BY',
            'GROUP', 'HAVING', 'AS', 'INNER', 'LEFT', 'RIGHT', 'OUTER', 'JOIN',
            'ON', 'UNION', 'ALL', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'SET',
            'DELETE', 'CREATE', 'TABLE', 'DROP', 'ALTER', 'INDEX', 'VIEW',
            'CASE', 'WHEN', 'THEN', 'ELSE', 'END', 'IS', 'NULL', 'IN', 'LIKE',
            'BETWEEN', 'EXISTS', 'DISTINCT', 'LIMIT', 'OFFSET', 'ASC', 'DESC',
            'WITH', 'OVER', 'PARTITION', 'USING', 'BEGIN', 'COMMIT', 'ROLLBACK',
            'TRANSACTION', 'IF', 'ELSE', 'WHILE', 'FOR', 'LOOP', 'FOREIGN',
            'PRIMARY', 'KEY', 'CONSTRAINT', 'DEFAULT', 'UNIQUE', 'CHECK',
            'REFERENCES', 'CASCADE', 'RESTRICT', 'GRANT', 'REVOKE',
            'TEMPORARY', 'TEMP', 'TRIGGER', 'BEFORE', 'AFTER', 'INSTEAD',
            'OF', 'EACH', 'ROW', 'EXECUTE', 'LANGUAGE', 'FUNCTION', 'RETURNS',
            'RETURN', 'DECLARE', 'FETCH', 'CURSOR', 'EXPLAIN'
        ]
        
        # 各句子特定关键字
        self.clause_keywords = {
            "SELECT": ["DISTINCT", "TOP", "ALL"],
            "FROM": ["JOIN", "INNER JOIN", "LEFT JOIN", "RIGHT JOIN", "FULL JOIN", "CROSS JOIN"],
            "WHERE": ["AND", "OR", "NOT", "IN", "BETWEEN", "LIKE", "IS NULL", "IS NOT NULL"],
            "GROUP BY": ["HAVING", "WITH ROLLUP", "WITH CUBE"],
            "ORDER BY": ["ASC", "DESC", "NULLS FIRST", "NULLS LAST"],
            "JOIN": ["ON", "USING"],
        }
        
        # SQL函数
        functions = [
            'COUNT', 'SUM', 'AVG', 'MIN', 'MAX', 'COALESCE', 'NULLIF', 'CAST',
            'EXTRACT', 'SUBSTRING', 'SUBSTR', 'TRIM', 'UPPER', 'LOWER', 'DATE_TRUNC',
            'DATE_PART', 'TO_CHAR', 'TO_DATE', 'LENGTH', 'ROUND', 'CEIL', 'FLOOR', 'ABS',
            'CONCAT', 'REPLACE', 'REGEXP_MATCHES', 'LAG', 'LEAD', 'RANK',
            'ROW_NUMBER', 'DENSE_RANK', 'ARRAY_AGG', 'STRING_AGG', 'JSON_AGG',
            'FIRST', 'LAST', 'NTH_VALUE', 'NTILE', 'VARIANCE', 'STDDEV',
            'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'NOW',
            'DATE_ADD', 'DATE_SUB', 'DATEDIFF', 'DATEADD', 'CONVERT', 'TRY_CAST',
            'FORMAT', 'LEFT', 'RIGHT', 'CHARINDEX', 'POSITION', 'INSTR',
            'YEAR', 'MONTH', 'DAY', 'HOUR', 'MINUTE', 'SECOND',
            'POWER', 'SQRT', 'LN', 'LOG', 'LOG10', 'EXP', 'MOD', 'RANDOM',
            'STRING_SPLIT', 'ARRAY_CONTAINS', 'JSON_EXTRACT', 'REGEXP_REPLACE'
        ]
        
        # DuckDB特有函数
        duckdb_functions = [
            'READ_CSV', 'READ_CSV_AUTO', 'READ_PARQUET', 'READ_JSON',
            'CURRENT_SCHEMA', 'PRAGMA_TABLE_INFO', 'LIST', 'LIST_TABLES',
            'DESCRIBE', 'EXPLAIN', 'GENERATE_SERIES', 'UNNEST', 'STRUCT_PACK',
            'STRUCT_EXTRACT', 'LIST_EXTRACT', 'LIST_CONCAT', 'LIST_APPEND',
            'MAP', 'MAP_EXTRACT', 'STRING_SPLIT_REGEX', 'REGEX_REPLACE',
            'FROM_JSON', 'TO_JSON', 'PARQUET_SCAN', 'JSON_EXTRACT_STRING',
            'JSON_TRANSFORM', 'ARRAY_SLICE', 'RANGE', 'IFNULL'
        ]
        
        # 创建补全项
        self.all_keywords = [
            CompletionItem(kw, CompletionItem.TYPE_KEYWORD, "SQL关键字", 150) 
            for kw in keywords
        ]
        
        self.all_functions = [
            CompletionItem(
                f"{func}()", 
                CompletionItem.TYPE_FUNCTION, 
                "SQL函数", 
                80,
                insert_text=f"{func}("
            ) 
            for func in functions
        ]
        
        self.duckdb_functions = [
            CompletionItem(
                f"{func}()", 
                CompletionItem.TYPE_FUNCTION, 
                "DuckDB特有函数", 
                80,
                insert_text=f"{func}("
            ) 
            for func in duckdb_functions
        ]
        
    def _connect_editor_signals(self):
        """连接编辑器的信号"""
        if hasattr(self.editor, 'textChanged'):
            self.editor.textChanged.connect(self._on_text_changed)
            
        # 添加鼠标点击事件监听
        if hasattr(self.editor, 'mousePressEvent'):
            # 保存原始的鼠标点击事件处理函数
            self._original_mouse_press_event = self.editor.mousePressEvent
            
            # 创建新的鼠标点击事件处理函数，先隐藏补全框再调用原始处理函数
            def mouse_press_event_with_completion_hide(event):
                # 如果补全窗口正在显示，则隐藏它
                if self.popup and self.popup.isVisible():
                    self.popup.hide()
                # 调用原始的鼠标点击事件处理函数
                self._original_mouse_press_event(event)
            
            # 替换编辑器的鼠标点击事件处理函数
            self.editor.mousePressEvent = mouse_press_event_with_completion_hide
        
        # 为编辑器添加事件过滤器，以处理其他事件
        self.editor.installEventFilter(self)
            
        # 处理编辑器焦点变化事件
        if hasattr(self.editor, 'focusOutEvent'):
            # 保存原始的焦点失去事件处理函数
            self._original_focus_out_event = self.editor.focusOutEvent
            
            # 创建新的焦点失去事件处理函数
            def focus_out_event_with_completion_hide(event):
                # 隐藏补全窗口
                if self.popup and self.popup.isVisible():
                    self.popup.hide()
                # 调用原始的焦点失去事件处理函数
                self._original_focus_out_event(event)
            
            # 替换编辑器的焦点失去事件处理函数
            self.editor.focusOutEvent = focus_out_event_with_completion_hide
        
    def _on_text_changed(self):
        """文本变化处理"""
        # 如果补全窗口可见，那么动态更新补全选项
        if self.popup.isVisible():
            QTimer.singleShot(10, self.show_completions)
            return
        
        # 自动触发补全的字符
        cursor = self.editor.textCursor()
        block = cursor.block()
        line = block.text()
        position = cursor.positionInBlock()
        
        # 跳过如果位置无效
        if position <= 0 or not line:
            return
        
        # 检查当前字符前一个字符
        prev_char = line[position-1:position]
        
        # 触发补全的字符：点号、非空格字符
        if prev_char == '.':
            QTimer.singleShot(10, self.show_completions)
        # 如果用户输入了至少2个字符，显示补全
        elif position >= 2 and all(c.isalnum() or c == '_' for c in line[position-2:position]):
            QTimer.singleShot(10, self.show_completions)
        
    def show_completions(self):
        """显示补全窗口"""
        # 获取当前行和光标位置
        cursor = self.editor.textCursor()
        block = cursor.block()
        line = block.text()
        position = cursor.positionInBlock()
        
        # 检查是否需要从设置中重新读取备用模式设置
        if hasattr(self, 'is_macos') and self.is_macos:
            from config.settings import settings
            force_fallback = settings.get("use_fallback_completion", False)
            if force_fallback:
                self.use_fallback_completion = True
                logger.info("根据用户设置使用备用补全模式")
        
        # 添加调试日志
        logger.info(f"尝试显示补全窗口：当前行文本: '{line[:position]}|{line[position:]}'")
        
        # 获取当前单词
        current_word, word_start = self._get_word_under_cursor(line, position)
        logger.info(f"光标下的单词: '{current_word}', 起始位置: {word_start}")
        
        # 获取整个编辑器内容
        full_text = self._get_full_query()
        # 计算光标在整个文档中的位置
        cursor_pos = cursor.position()
        
        # 检查是否在字符串内部
        if self._is_in_string_literal(full_text, cursor_pos):
            # 在字符串内部不提供补全，除非是特定模式
            string_context = self._get_string_context(full_text, cursor_pos)
            # 这里可以实现特定字符串内的补全，例如文件路径等
            
            # 当前默认在字符串中不补全
            logger.info("光标在字符串内部，不显示补全窗口")
            self.popup.hide()
            return
        
        # 如果光标前面没有文本，不显示补全
        if not current_word and word_start == 0 and position > 0 and line[position-1] not in ['.', ' ']:
            logger.info("光标前没有有效文本，不显示补全窗口")
            self.popup.hide()
            return
            
        # 检查是否在SQL关键字后面，如果是则降低字符长度要求
        is_after_sql_keyword = False
        context_before = line[:position].strip().upper()
        sql_keywords = ['SELECT', 'FROM', 'WHERE', 'GROUP BY', 'ORDER BY', 'HAVING', 'INSERT', 'UPDATE', 'DELETE']
        for keyword in sql_keywords:
            if context_before.endswith(keyword):
                is_after_sql_keyword = True
                break

        # 如果当前单词太短（少于2个字符）且不是特殊触发情况，不显示补全
        min_word_length = 1 if is_after_sql_keyword else 2  # SQL关键字后面只需要1个字符就能触发
        if (len(current_word) < min_word_length and 
            not line[:position].endswith('.') and  # 不是表.列的情况
            not (position == 0 or re.match(r'^\s*$', line[:position])) and  # 不是行首
            not is_after_sql_keyword):  # 不是SQL关键字后面
            logger.info(f"当前单词太短: '{current_word}'，不显示补全窗口")
            self.popup.hide()
            return
            
        # 获取补全项
        completion_items = self._get_completion_items(line, position, current_word)
        
        # 如果没有补全项，隐藏弹出窗口
        if not completion_items:
            logger.info("没有找到补全项，不显示补全窗口")
            self.popup.hide()
            return
            
        logger.info(f"找到 {len(completion_items)} 个补全项")
        
        # 检查是否需要使用备用补全方式
        current_time = time.time()
        if hasattr(self, 'is_macos') and self.is_macos:
            # 如果最近的显示尝试间隔很短并且窗口未能正常显示，使用备用模式
            if (hasattr(self, 'last_popup_time') and current_time - self.last_popup_time < 1.0 and 
                hasattr(self, 'popup_show_attempts') and self.popup_show_attempts > 2 and
                hasattr(self, 'popup_visible') and not self.popup_visible):
                self.use_fallback_completion = True
                logger.warning("使用备用补全模式 - 补全窗口显示不稳定")
        
        if hasattr(self, 'last_popup_time'):
            self.last_popup_time = current_time
        if hasattr(self, 'popup_show_attempts'):
            self.popup_show_attempts += 1
            
        # 使用备用补全方式 - 在编辑器中直接显示一些选项
        if hasattr(self, 'use_fallback_completion') and self.use_fallback_completion and hasattr(self, 'is_macos') and self.is_macos:
            logger.info("使用备用补全模式显示选项")
            
            # 在状态标签中显示补全选项
            # 查找编辑器所在的标签页
            parent = self.editor.parent()
            status_label = None
            
            # 尝试找到状态标签
            while parent and not status_label:
                if hasattr(parent, 'status_label'):
                    status_label = parent.status_label
                    break
                parent = parent.parent()
                
            if status_label:
                # 提取前5个补全项的文本
                top_options = [item.text for item in completion_items[:5]]
                status_text = f"补全选项: {', '.join(top_options)}"
                try:
                    status_label.setText(status_text)
                except:
                    pass
                    
            # 在编辑器中直接处理第一个补全项
            if completion_items and current_word:
                first_item = completion_items[0]
                
                # 显示一个工具提示，提示可用的补全项
                tool_tip_text = "按 Tab 键接受: " + "\n".join([item.text for item in completion_items[:7]])
                self.editor.setToolTip(tool_tip_text)
                
                # 1秒后隐藏工具提示
                QTimer.singleShot(5000, lambda: self.editor.setToolTip(""))
            
            return
            
        # 检查项目是否有变化，如果没有，保持当前选中项
        current_selected = -1
        if self.popup.isVisible() and self.popup.list_widget.count() > 0:
            current_selected = self.popup.list_widget.currentRow()
            
            # 检查当前项目列表是否与之前相同
            if len(completion_items) == len(self.current_items):
                same_items = True
                for i, (new_item, old_item) in enumerate(zip(completion_items, self.current_items)):
                    if new_item.text != old_item.text or new_item.type != old_item.type:
                        same_items = False
                        break
                        
                if same_items:
                    # 不需要刷新整个列表，保持当前选中项
                    pass
                    
        # 设置补全项
        self.popup.set_items(completion_items)
        self.current_items = completion_items
        
        # 计算弹出窗口位置
        rect = self.editor.cursorRect()
        
        # 获取当前行的矩形区域
        cursor = self.editor.textCursor()
        current_block = cursor.block()
        
        # 计算当前行的底部位置，而不是光标的底部位置
        line_height = self.editor.fontMetrics().height()
        
        # 使用更简单的方法：光标位置的X坐标 + 当前行底部的Y坐标
        # 添加小间距避免紧贴文本
        line_bottom_y = rect.bottom() + 3  # 添加3px间距
        line_bottom_local = QPoint(rect.left(), line_bottom_y)
        global_pos = self.editor.mapToGlobal(line_bottom_local)
        
        # 检测操作系统
        import platform
        is_macos = platform.system() == 'Darwin'
        logger.info(f"当前操作系统: {'macOS' if is_macos else '非macOS'}")
        
        # 确保补全框尺寸适中
        self.popup.setMaximumWidth(400)
        self.popup.setMaximumHeight(300)
        
        # 获取屏幕几何信息，确保不超出屏幕边界
        screen_geometry = QGuiApplication.primaryScreen().availableGeometry()
        
        # 调整 X 坐标确保不超出屏幕右侧
        popup_x = min(global_pos.x(), screen_geometry.right() - self.popup.width())
        
        # 调整 Y 坐标，如果底部显示会超出屏幕，则在当前行上方显示
        popup_y = global_pos.y()
        if popup_y + self.popup.height() > screen_geometry.bottom():
            # 在当前行上方显示，而不是光标上方
            line_height = self.editor.fontMetrics().height()
            popup_y = global_pos.y() - self.popup.height() - line_height - 5  # 添加5px间距
            popup_y = max(popup_y, screen_geometry.top())  # 确保不超出屏幕顶部
        
        logger.info(f"补全窗口位置: x={popup_x}, y={popup_y}")
        
        if is_macos:
            # macOS 特定处理
            logger.info("使用 macOS 特定显示方法")
            
            # 在 macOS 上，不要在补全窗口显示时设置其父窗口为 None
            # 保持原有的父窗口关系更稳定
            if self.popup.parent() is None:
                self.popup.setParent(self.editor.window())
                
            self.popup.setWindowFlags(Qt.ToolTip | Qt.FramelessWindowHint)
            self.popup.move(popup_x, popup_y)
            self.popup.show()
            
            # 使用 Timer 延迟提升窗口，避免闪退
            QTimer.singleShot(10, self.popup.raise_)
            
            # 添加额外的状态跟踪
            if hasattr(self, 'popup_visible'):
                self.popup_visible = True
        else:
            # 其他平台处理
            logger.info("使用标准显示方法")
            editor_window = self.editor.window()
            if editor_window:
                # 使用父窗口坐标
                parent_pos = editor_window.mapFromGlobal(QPoint(popup_x, popup_y))
                logger.info(f"父窗口坐标: x={parent_pos.x()}, y={parent_pos.y()}")
                self.popup.setParent(editor_window)
                self.popup.move(parent_pos)
            else:
                # 使用全局坐标
                logger.info("无法获取父窗口，使用全局坐标")
                self.popup.setParent(None)
                self.popup.move(popup_x, popup_y)
                
            self.popup.show()
        
        logger.info("补全窗口已显示")
        
        # 恢复或设置当前选中项
        if current_selected >= 0 and current_selected < self.popup.list_widget.count():
            self.popup.list_widget.setCurrentRow(current_selected)
        elif self.popup.list_widget.count() > 0:
            self.popup.list_widget.setCurrentRow(0)
        
    def _get_word_under_cursor(self, line: str, position: int) -> Tuple[str, int]:
        """获取光标下的单词
        
        Args:
            line: 当前行文本
            position: 光标在行中的位置
            
        Returns:
            (当前单词, 单词起始位置)
        """
        # 如果光标在行末或行为空，返回空字符串
        if position <= 0 or not line:
            return "", 0
            
        # 向前查找单词的起始位置
        start = position
        while start > 0 and (line[start-1].isalnum() or line[start-1] == '_' or line[start-1] == '.'):
            start -= 1
            
        # 提取单词
        word = line[start:position]
        
        return word, start
        
    def _get_completion_items(self, line: str, position: int, 
                             current_word: str) -> List[CompletionItem]:
        """获取补全项
        
        Args:
            line: 当前行文本
            position: 光标位置
            current_word: 当前单词
            
        Returns:
            补全项列表
        """
        items = []
        # 跟踪已添加的补全项以避免重复
        added_items = set()
        
        # 获取完整SQL语句及上下文
        full_sql = self._get_full_query()
        context = self._get_completion_context(line, position)
        
        # 确定当前所处的SQL子句
        clause_type = self._detect_sql_clause(context.upper(), context)
        
        # 1. 处理表后跟点号的情况（优先处理，显示对应表的列）
        match = re.search(r'(\w+)\.(\w*)$', line[:position])
        if match:
            table_or_alias = match.group(1)
            partial_col = match.group(2) or ""
            
            # 确定真实表名
            real_table = self.table_aliases.get(table_or_alias, table_or_alias)
            
            # 检查是否有此表的列信息
            if real_table in self.table_columns:
                columns = self.table_columns[real_table]
                # 依据前缀过滤列
                matched_columns = []
                for col in columns:
                    if not partial_col or col.lower().startswith(partial_col.lower()):
                        col_type = self.column_type_mappings.get(f"{real_table}.{col}", "")
                        desc = f"{real_table}表的列"
                        if col_type:
                            desc += f" [{col_type}]"
                        matched_columns.append(
                            CompletionItem(col, CompletionItem.TYPE_COLUMN, desc, 100, col_type)
                        )
                
                # 按列名排序
                matched_columns.sort(key=lambda x: x.text.lower())
                
                # 限制列数量
                max_cols = min(len(matched_columns), self.MAX_ITEMS)
                return matched_columns[:max_cols]
        
        # 2. 处理字符串字面量内部的情况
        if clause_type == "STRING_LITERAL":
            # 在字符串内部不提供补全
            return []
            
        # 3. 处理SQL代码片段（行首或语句开始位置）
        if position == 0 or re.match(r'^\s*$', line[:position]):
            for snippet_key, snippet_item in self.sql_snippets.items():
                if not current_word or snippet_key.startswith(current_word.lower()):
                    items.append(snippet_item)
                    added_items.add(snippet_key)
            
            # 如果是空白或刚开始，优先添加常见查询开始关键字
            if not current_word or current_word.isspace():
                start_keywords = ["SELECT", "WITH", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "ALTER"]
                for kw in start_keywords:
                    kw_key = f"kw_{kw.lower()}"
                    if kw_key not in added_items:
                        items.append(CompletionItem(kw, CompletionItem.TYPE_KEYWORD, "SQL关键字", 150))
                        added_items.add(kw_key)
                return items
        
        # 4. 处理表别名定义
        if clause_type == "TABLE_ALIAS":
            # 不提供具体补全，只显示AS关键字提示
            if not current_word or "AS".lower().startswith(current_word.lower()):
                items.append(CompletionItem("AS", CompletionItem.TYPE_KEYWORD, "定义表别名", 150))
            return items
            
        # 5. 处理表列的别名定义
        if clause_type == "ALIAS":
            # 不提供具体补全，仅作占位
            return []
            
        # 6. 处理插入值
        if clause_type == "INSERT_VALUES":
            # 提取插入语句中的表名
            match = re.search(r'INSERT\s+INTO\s+(\w+)', full_sql, re.IGNORECASE)
            if match:
                table_name = match.group(1)
                # 添加NULL和DEFAULT等特殊值
                special_values = ["NULL", "DEFAULT", "CURRENT_TIMESTAMP", "TRUE", "FALSE"]
                for val in special_values:
                    val_key = f"val_{val.lower()}"
                    if not current_word or val.lower().startswith(current_word.lower()):
                        if val_key not in added_items:
                            items.append(CompletionItem(val, CompletionItem.TYPE_KEYWORD, "SQL值", 120))
                            added_items.add(val_key)
            return items
            
        # 7. 处理CREATE TABLE语句
        if clause_type == "CREATE_TABLE":
            # 添加常见的数据类型
            data_types = ["INT", "INTEGER", "BIGINT", "SMALLINT", "TINYINT", 
                         "FLOAT", "DOUBLE", "DECIMAL", "NUMERIC",
                         "CHAR", "VARCHAR", "TEXT", "BLOB", 
                         "DATE", "TIME", "TIMESTAMP", "DATETIME",
                         "BOOLEAN", "BIT", "JSON", "ARRAY",
                         "SERIAL", "UUID", "ENUM"]
            
            # 添加约束关键字
            constraints = ["PRIMARY KEY", "FOREIGN KEY", "UNIQUE", "NOT NULL", 
                           "DEFAULT", "CHECK", "REFERENCES", "CONSTRAINT"]
            
            for item in data_types + constraints:
                item_key = f"dt_{item.lower().replace(' ', '_')}"
                if not current_word or item.lower().startswith(current_word.lower()):
                    if item_key not in added_items:
                        items.append(CompletionItem(item, CompletionItem.TYPE_KEYWORD, "数据类型/约束", 120))
                        added_items.add(item_key)
            return items
        
        # 8. 处理其他子句
        if clause_type in self.clause_keywords:
            # 添加子句关键字
            for kw in self.clause_keywords[clause_type]:
                if not current_word or kw.lower().startswith(current_word.lower()):
                    if f"kw_{kw.lower()}" not in added_items:
                        items.append(CompletionItem(kw, CompletionItem.TYPE_KEYWORD, "SQL关键字", 150))
                        added_items.add(f"kw_{kw.lower()}")
            
            # 添加列名
            column_added = 0
            max_cols = self.MAX_ITEMS - len(items)
            
            # 首先尝试从查询中获取列名
            all_columns = self._get_all_columns_from_query(full_sql)
            
            # 如果没有找到列名（比如SELECT后面没有FROM子句），则显示所有已知表的列
            if not all_columns and clause_type == "SELECT":
                # 显示所有已知表的列名，但不带表前缀（在SELECT中更自然）
                for table_name, columns in self.table_columns.items():
                    for col in columns:
                        if column_added >= max_cols:
                            break
                        if not current_word or col.lower().startswith(current_word.lower()):
                            col_key = f"col_{table_name}_{col.lower()}"
                            if col_key not in added_items:
                                col_type = self.column_type_mappings.get(f"{table_name}.{col}", "")
                                desc = f"{table_name}表的列"
                                if col_type:
                                    desc += f" [{col_type}]"
                                items.append(CompletionItem(col, CompletionItem.TYPE_COLUMN, desc, 100, col_type))
                                added_items.add(col_key)
                                column_added += 1
            
                # 同时也显示带表前缀的列名（表.列）
                for table_name, columns in self.table_columns.items():
                    for col in columns:
                        if column_added >= max_cols:
                            break
                        qualified_col = f"{table_name}.{col}"
                        if not current_word or qualified_col.lower().startswith(current_word.lower()):
                            qual_col_key = f"qual_col_{table_name}_{col.lower()}"
                            if qual_col_key not in added_items:
                                col_type = self.column_type_mappings.get(f"{table_name}.{col}", "")
                                desc = f"{table_name}表的列"
                                if col_type:
                                    desc += f" [{col_type}]"
                                items.append(CompletionItem(qualified_col, CompletionItem.TYPE_COLUMN, desc, 95, col_type))
                                added_items.add(qual_col_key)
                                column_added += 1
            else:
                # 处理从查询中提取的列名
                for col in all_columns:
                    if column_added >= max_cols:
                        break
                        
                    if not current_word or col.lower().startswith(current_word.lower()):
                        parts = col.split('.')
                        if len(parts) == 2:
                            table, column = parts
                            real_table = self.table_aliases.get(table, table)
                            col_type = self.column_type_mappings.get(f"{real_table}.{column}", "")
                            desc = f"{real_table}表的列"
                            if col_type:
                                desc += f" [{col_type}]"
                            items.append(CompletionItem(col, CompletionItem.TYPE_COLUMN, desc, 100, col_type))
                        else:
                            # 寻找此列属于哪个表
                            for table in self._extract_tables_from_query(full_sql):
                                real_table = self.table_aliases.get(table, table)
                                if real_table in self.table_columns and col in self.table_columns[real_table]:
                                    col_type = self.column_type_mappings.get(f"{real_table}.{col}", "")
                                    desc = f"{real_table}表的列"
                                    if col_type:
                                        desc += f" [{col_type}]"
                                    items.append(CompletionItem(col, CompletionItem.TYPE_COLUMN, desc, 100, col_type))
                                    column_added += 1
                                    break
                            else:
                                # 如果没找到，就作为普通列添加
                                items.append(CompletionItem(col, CompletionItem.TYPE_COLUMN, "列", 100))
                                column_added += 1
            
            # 添加函数
            if clause_type in ["SELECT", "WHERE", "HAVING", "ON", "CASE"]:
                func_added = 0
                max_funcs = self.MAX_ITEMS - len(items)
                
                # 根据子句类型选择优先显示的函数
                priority_funcs = []
                if clause_type == "SELECT":
                    priority_funcs = ["COUNT", "SUM", "AVG", "MIN", "MAX", "GROUP_CONCAT"]
                elif clause_type in ["WHERE", "HAVING", "ON"]:
                    priority_funcs = ["COALESCE", "NULLIF", "CASE", "CAST", "CONVERT"]
                elif clause_type == "CASE":
                    priority_funcs = ["WHEN", "THEN", "ELSE", "END"]
                
                # 先添加优先函数
                for func_name in priority_funcs:
                    if func_added >= max_funcs:
                        break
                        
                    func_text = f"{func_name}()"
                    func_key = f"func_{func_name.lower()}"
                    
                    if not current_word or func_name.lower().startswith(current_word.lower()):
                        if func_key not in added_items:
                            items.append(CompletionItem(
                                func_text,
                                CompletionItem.TYPE_FUNCTION,
                                "常用函数",
                                110,
                                f"{func_name}函数",
                                f"{func_name}("
                            ))
                            added_items.add(func_key)
                            func_added += 1
                
                # 添加其他匹配的函数
                for func in self.all_functions + self.duckdb_functions:
                    if func_added >= max_funcs:
                        break
                    
                    if not current_word or func.text.lower().startswith(current_word.lower()):
                        func_name = func.text.replace("()", "")
                        func_key = f"func_{func_name.lower()}"
                        
                        if func_key not in added_items:
                            items.append(func)
                            added_items.add(func_key)
                            func_added += 1
            
            # 添加表名（针对FROM和JOIN子句）
            if clause_type in ["FROM", "JOIN"]:
                table_added = 0
                max_tables = self.MAX_ITEMS - len(items)
                tables = self._get_all_tables()
                
                for table in tables:
                    if table_added >= max_tables:
                        break
                        
                    if not current_word or table.lower().startswith(current_word.lower()):
                        # 获取表的列数
                        col_count = len(self.table_columns.get(table, []))
                        column_desc = f"{col_count}列" if col_count > 0 else "无列信息"
                        
                        table_key = f"tbl_{table.lower()}"
                        if table_key not in added_items:
                            items.append(CompletionItem(
                                table, 
                                CompletionItem.TYPE_TABLE, 
                                f"表 ({column_desc})", 
                                120,
                                f"表: {table}"
                            ))
                            added_items.add(table_key)
                            table_added += 1
            
            # ORDER BY子句的特殊处理
            if clause_type == "ORDER BY":
                # 添加排序方向关键字
                for dir_kw in ["ASC", "DESC", "NULLS FIRST", "NULLS LAST"]:
                    dir_key = f"dir_{dir_kw.lower().replace(' ', '_')}"
                    if not current_word or dir_kw.lower().startswith(current_word.lower()):
                        if dir_key not in added_items:
                            items.append(CompletionItem(
                                dir_kw,
                                CompletionItem.TYPE_KEYWORD,
                                "排序方向",
                                140,
                                "排序"
                            ))
                            added_items.add(dir_key)
        
        # 如果没有匹配的项目或很少的项目，添加常用SQL元素
        if len(items) < 5:
            # 1. 添加匹配的关键字
            kw_added = 0
            max_kw = min(10, self.MAX_ITEMS - len(items))
            for kw in self.all_keywords:
                if kw_added >= max_kw:
                    break
                    
                kw_text = kw.text  # CompletionItem.text
                kw_key = f"kw_{kw_text.lower()}"
                
                if not current_word or kw_text.lower().startswith(current_word.lower()):
                    if kw_key not in added_items:
                        items.append(kw)
                        added_items.add(kw_key)
                        kw_added += 1
            
            # 2. 添加匹配的表名
            if len(items) < 10:
                table_added = 0
                max_tables = min(10, self.MAX_ITEMS - len(items))
                tables = self._get_all_tables()
                
                for table in tables:
                    if table_added >= max_tables:
                        break
                        
                    table_key = f"tbl_{table.lower()}"
                    if not current_word or table.lower().startswith(current_word.lower()):
                        if table_key not in added_items:
                            col_count = len(self.table_columns.get(table, []))
                            column_desc = f"{col_count}列" if col_count > 0 else "无列信息"
                            items.append(CompletionItem(
                                table, 
                                CompletionItem.TYPE_TABLE, 
                                f"表 ({column_desc})", 
                                80,
                                f"表: {table}"
                            ))
                            added_items.add(table_key)
                            table_added += 1
        
        # 添加最近使用过的补全项（优先级最高）
        if len(self.recent_completions) > 0:
            recent_added = 0
            for item in self.recent_completions:
                if recent_added >= 5:  # 限制最近项数量
                    break
                    
                if not current_word or item.text.lower().startswith(current_word.lower()):
                    item_key = f"recent_{item.text.lower().replace(' ', '_')}"
                    
                    if item_key not in added_items:
                        # 创建副本并提高优先级
                        item_copy = CompletionItem(
                            item.text,
                            item.type,
                            f"最近使用: {item.description}" if item.description else "最近使用",
                            200,  # 最高优先级
                            item.detail,
                            item.insert_text
                        )
                        if item.type == CompletionItem.TYPE_KEYWORD and item.text.upper() in added_items:
                            continue  # 跳过已添加的关键字
                        items.append(item_copy)
                        added_items.add(item_key)
                        recent_added += 1
        
        # 按优先级排序补全项
        items.sort(key=lambda x: (-x.priority, x.text.lower()))
        
        return items[:self.MAX_ITEMS]

    def _get_full_query(self) -> str:
        """获取当前编辑器中的完整SQL查询"""
        if hasattr(self.editor, 'toPlainText'):
            return self.editor.toPlainText()
        return ""
    
    def _get_all_tables(self) -> List[str]:
        """获取所有可用的表名
        
        Returns:
            表名列表
        """
        tables = []
        try:
            db = get_db_engine()
            table_infos = db.get_loaded_tables()
            
            # 添加表名和描述
            for table_info in table_infos:
                table_name = table_info['table_name']
                tables.append(table_name)
                
        except Exception as e:
            logger.error(f"获取表名时出错: {str(e)}")
        
        return tables
            
    def _get_all_columns_from_query(self, query: str) -> List[str]:
        """从查询中提取所有可能的列名
        
        Args:
            query: SQL查询语句
            
        Returns:
            列名列表
        """
        columns = []
        
        # 从表中获取列
        tables = self._extract_tables_from_query(query)
        for table in tables:
            # 处理表别名
            if ' AS ' in table.upper():
                parts = re.split(r'\s+AS\s+', table, flags=re.IGNORECASE)
                real_table = parts[0].strip().strip('"\'[]')
                alias = parts[1].strip().strip('"\'[]')
                self.table_aliases[alias] = real_table
                table = real_table
                
            # 添加此表的所有列
            if table in self.table_columns:
                table_cols = self.table_columns[table]
                columns.extend([col for col in table_cols])
                # 也添加表名限定的列名
                columns.extend([f"{table}.{col}" for col in table_cols])
        
        # 添加任何别名限定的列名
        for alias, real_table in self.table_aliases.items():
            if real_table in self.table_columns:
                columns.extend([f"{alias}.{col}" for col in self.table_columns[real_table]])
            
        return columns
        
    def _get_completion_context(self, line: str, position: int) -> str:
        """获取补全上下文
        
        Args:
            line: 当前行文本
            position: 光标在行中的位置
            
        Returns:
            当前SQL上下文
        """
        # 返回光标前的文本
        return line[:position]
        
    def _extract_tables_from_query(self, query: str) -> List[str]:
        """从查询中提取表名及别名
        
        Args:
            query: SQL查询文本
            
        Returns:
            表名列表
        """
        tables = []
        
        # 如果查询为空，返回空列表
        if not query:
            return tables
            
        # 预处理：去除SQL注释
        query = re.sub(r'--.*?$', ' ', query, flags=re.MULTILINE)  # 单行注释
        query = re.sub(r'/\*.*?\*/', ' ', query, flags=re.DOTALL)  # 多行注释
        
        # 规范化空白字符
        query = re.sub(r'\s+', ' ', query)
        
        # 处理子查询中的表
        # 用正则表达式匹配()中的内容，递归处理子查询
        subquery_pattern = r'\(\s*(SELECT.*?)\s*\)'
        subqueries = re.finditer(subquery_pattern, query, re.IGNORECASE | re.DOTALL)
        for match in subqueries:
            subquery = match.group(1)
            # 递归处理子查询中的表
            subtables = self._extract_tables_from_query(subquery)
            
            # 检查子查询是否有别名
            sub_end_pos = match.end()
            if sub_end_pos < len(query):
                alias_match = re.search(r'^\s+(?:AS\s+)?(\w+)', query[sub_end_pos:], re.IGNORECASE)
                if alias_match:
                    alias = alias_match.group(1)
                    # 子查询的所有表列都可以通过此别名访问
                    self.table_aliases[alias] = f"subquery_{len(self.table_aliases)}"
        
        # 1. 匹配 FROM 子句后的表名（基本模式）
        # 匹配 FROM table, table2, table3
        from_clause = re.search(r'FROM\s+(.*?)(?:\s+(?:WHERE|GROUP\s+BY|HAVING|ORDER\s+BY|LIMIT|$))', 
                               query, re.IGNORECASE | re.DOTALL)
        if from_clause:
            from_tables = from_clause.group(1).split(',')
            for table_entry in from_tables:
                # 处理复杂情况前先尝试提取基本表名
                parts = re.split(r'\s+(?:AS\s+)?', table_entry.strip(), maxsplit=1, flags=re.IGNORECASE)
                if parts:
                    table_name = parts[0].strip().strip('"\'`[]')
                    
                    # 如果不是子查询或CTE，则添加到表列表
                    if not (table_name.startswith('(') or table_name.startswith('WITH')):
                        tables.append(table_name)
                        
                        # 如果有别名，记录别名
                        if len(parts) > 1:
                            alias = parts[1].strip().strip('"\'`[]')
                            self.table_aliases[alias] = table_name
        
        # 2. 匹配 JOIN 子句中的表名
        # 支持各种JOIN类型: INNER, LEFT, RIGHT, FULL, CROSS
        join_pattern = r'(?:INNER|LEFT|RIGHT|FULL|CROSS)?\s*JOIN\s+(\w+(?:\.\w+)?|\[.*?\]|".*?"|\'.*?\')\s+(?:AS\s+)?(\w+)?'
        join_matches = re.finditer(join_pattern, query, re.IGNORECASE)
        for match in join_matches:
            table_name = match.group(1).strip().strip('"\'`[]')
            tables.append(table_name)
            
            # 记录别名
            if match.group(2):
                alias = match.group(2).strip()
                self.table_aliases[alias] = table_name
                
        # 3. 匹配 UPDATE 语句的表名
        update_match = re.search(r'UPDATE\s+(\w+(?:\.\w+)?|\[.*?\]|".*?"|\'.*?\')', query, re.IGNORECASE)
        if update_match:
            table_name = update_match.group(1).strip().strip('"\'`[]')
            tables.append(table_name)
            
        # 4. 匹配 INSERT INTO 语句的表名
        insert_match = re.search(r'INSERT\s+INTO\s+(\w+(?:\.\w+)?|\[.*?\]|".*?"|\'.*?\')', query, re.IGNORECASE)
        if insert_match:
            table_name = insert_match.group(1).strip().strip('"\'`[]')
            tables.append(table_name)
            
        # 5. 匹配 DELETE FROM 语句的表名
        delete_match = re.search(r'DELETE\s+FROM\s+(\w+(?:\.\w+)?|\[.*?\]|".*?"|\'.*?\')', query, re.IGNORECASE)
        if delete_match:
            table_name = delete_match.group(1).strip().strip('"\'`[]')
            tables.append(table_name)
            
        # 6. 匹配CTE (WITH语句)
        cte_matches = re.finditer(r'WITH\s+(\w+)\s+(?:AS\s+)?\(', query, re.IGNORECASE)
        for match in cte_matches:
            cte_name = match.group(1).strip()
            tables.append(cte_name)
            # CTE名可以作为表名使用
            self.table_aliases[cte_name] = cte_name
            
        # 去重并返回
        return list(dict.fromkeys(tables))
    
    def _detect_sql_clause(self, context_upper: str, full_context: str) -> str:
        """检测当前所处的SQL子句类型
        
        Args:
            context_upper: 上下文文本（大写）
            full_context: 完整上下文文本
            
        Returns:
            SQL子句类型
        """
        # 子句关键字及其模式，按优先级排序
        clause_patterns = [
            # 精确匹配模式，包含边界检查
            ("ON", r'\bON\b'),
            ("JOIN", r'\b(JOIN|INNER\s+JOIN|LEFT\s+JOIN|RIGHT\s+JOIN|FULL\s+JOIN|CROSS\s+JOIN)\b'),
            ("WHERE", r'\bWHERE\b'),
            ("GROUP BY", r'\bGROUP\s+BY\b'),
            ("HAVING", r'\bHAVING\b'),
            ("ORDER BY", r'\bORDER\s+BY\b'),
            ("LIMIT", r'\bLIMIT\b'),
            ("FROM", r'\bFROM\b'),
            ("SELECT", r'\bSELECT\b'),
            ("INSERT", r'\bINSERT\b'),
            ("UPDATE", r'\bUPDATE\b'),
            ("DELETE", r'\bDELETE\b'),
            ("WITH", r'\bWITH\b'),
            ("CASE", r'\bCASE\b'),
            ("WHEN", r'\bWHEN\b'),
            ("THEN", r'\bTHEN\b'),
            ("ELSE", r'\bELSE\b'),
            ("END", r'\bEND\b'),
        ]
        
        # 检查是否在引号内部（字符串字面量内）
        quote_positions = []
        for i, char in enumerate(full_context):
            if char in "\"'`":
                quote_positions.append(i)
                
        # 如果引号个数为奇数，则光标在引号内部
        if len(quote_positions) % 2 == 1:
            return "STRING_LITERAL"
            
        # 查找最后出现的子句
        last_clause = ""
        last_position = -1
        
        for clause, pattern in clause_patterns:
            # 使用更精确的正则表达式搜索
            matches = list(re.finditer(pattern, context_upper))
            if matches:
                # 获取最后一个匹配
                match = matches[-1]
                if match.start() > last_position:
                    # 检查是否在引号内部
                    in_quotes = False
                    for i in range(0, len(quote_positions), 2):
                        if i+1 < len(quote_positions):
                            if quote_positions[i] < match.start() < quote_positions[i+1]:
                                in_quotes = True
                                break
                    
                    if not in_quotes:
                        last_position = match.start()
                        last_clause = clause
        
        # 特殊情况处理
        
        # 检查CREATE TABLE情况
        if re.search(r'\bCREATE\s+TABLE\b', context_upper):
            return "CREATE_TABLE"
            
        # 检查选择列之后的AS别名情况
        if re.search(r'\bAS\s+\w*$', full_context, re.IGNORECASE):
            return "ALIAS"
            
        # 检查是否在INSERT INTO ... VALUES 之间
        if re.search(r'\bINSERT\s+INTO\s+.*?\s+VALUES\s*\(', context_upper, re.DOTALL):
            return "INSERT_VALUES"
            
        # 检查是否在表别名定义位置 (... FROM table AS 或 ... JOIN table AS)
        if re.search(r'\b(FROM|JOIN)\s+\w+\s+AS\s+\w*$', full_context, re.IGNORECASE):
            return "TABLE_ALIAS"
        
        # 如果找到了明确的子句
        if last_clause:
            return last_clause
        
        # 默认假设在SELECT子句中
        return "SELECT"
    
    def _get_context_keywords(self, clause_type: str) -> List[str]:
        """获取特定SQL子句的上下文关键字
        
        Args:
            clause_type: 子句类型
            
        Returns:
            关键字列表
        """
        if clause_type in self.clause_keywords:
            return self.clause_keywords[clause_type]
            
        # 根据不同子句返回不同的上下文关键字
        if clause_type == "ALIAS":
            return []  # AS后面通常是标识符，不需要关键字
        
        # 默认关键字
        return ["SELECT", "FROM", "WHERE", "GROUP BY", "HAVING", "ORDER BY", "LIMIT"]
        
    def _insert_completion(self, text: str):
        """插入补全文本
        
        Args:
            text: 要插入的文本
        """
        if not self.editor:
            return
            
        # 获取光标
        cursor = self.editor.textCursor()
        
        # 获取当前行文本
        block = cursor.block()
        line = block.text()
        position = cursor.positionInBlock()
        
        # 获取当前单词和起始位置
        current_word, word_start = self._get_word_under_cursor(line, position)
        
        # 删除当前单词
        cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, position - word_start)
        cursor.removeSelectedText()
        
        # 插入补全文本
        cursor.insertText(text)
        
        # 如果插入文本以()结尾，将光标放在括号内
        if text.endswith("()"):
            cursor.movePosition(QTextCursor.Left)
            
        # 更新编辑器光标
        self.editor.setTextCursor(cursor)
        
        # 隐藏补全窗口
        self.popup.hide()
        
        # 添加到最近使用的补全项
        for item in self.current_items:
            if item.insert_text == text:
                if item not in self.recent_completions:
                    self.recent_completions.insert(0, item)
                    # 限制最近使用项数量
                    if len(self.recent_completions) > 10:
                        self.recent_completions.pop()
                break
        
    def handle_key_press(self, event):
        """处理按键事件
        
        Args:
            event: 按键事件
            
        Returns:
            是否已处理事件
        """
        key = event.key()
        
        # 添加调试日志
        modifiers = event.modifiers()
        key_text = event.text()
        logger.debug(f"按键事件: key={key}, text='{key_text}', modifiers={modifiers}")
        
        # 处理备用补全模式下的Tab键
        if hasattr(self, 'use_fallback_completion') and self.use_fallback_completion and key == Qt.Key_Tab:
            if self.current_items and len(self.current_items) > 0:
                logger.info("备用模式: 使用Tab键接受第一个补全项")
                first_item = self.current_items[0]
                self._insert_completion(first_item.insert_text)
                # 重置备用模式状态
                self.use_fallback_completion = False
                return True
        
        # 补全窗口显示时的按键处理
        if self.popup.isVisible():
            if key in (Qt.Key_Up, Qt.Key_Down):
                # 上下键选择补全项
                direction = -1 if key == Qt.Key_Up else 1
                self.popup.move_selection(direction)
                return True
                
            elif key in (Qt.Key_Return, Qt.Key_Enter, Qt.Key_Tab):
                # 回车或Tab键确认选择当前高亮的补全项
                current_row = self.popup.list_widget.currentRow()
                logger.debug(f"当前选中行: {current_row}, 总项数: {len(self.current_items)}")
                
                if current_row >= 0 and current_row < len(self.current_items):
                    # 获取当前选中的补全项
                    selected_item = self.current_items[current_row]
                    logger.info(f"已选择补全项: '{selected_item.text}' -> '{selected_item.insert_text}'")
                    self._insert_completion(selected_item.insert_text)
                    return True
                elif len(self.current_items) > 0:
                    # 如果没有明确选中项但有补全项，选择第一个
                    first_item = self.current_items[0]
                    logger.info(f"选择第一个补全项: '{first_item.text}' -> '{first_item.insert_text}'")
                    self._insert_completion(first_item.insert_text)
                    return True
                else:
                    # 如果没有有效的选中项
                    if key in (Qt.Key_Return, Qt.Key_Enter):
                        # 回车键隐藏补全窗口并让编辑器处理换行
                        logger.debug("回车键: 隐藏补全窗口，让编辑器处理换行")
                        self.popup.hide()
                        return False
                    else:
                        # Tab键隐藏补全窗口但不插入任何内容
                        logger.debug("Tab键: 隐藏补全窗口")
                        self.popup.hide()
                        return True
                
            elif key == Qt.Key_Escape:
                # ESC键取消补全
                logger.info("ESC键取消补全")
                self.popup.hide()
                return True
                
            elif key == Qt.Key_Backspace:
                # 退格键正常处理，但需要重新评估补全
                # 不捕获退格键，让编辑器正常处理
                QTimer.singleShot(10, self.show_completions)
                return False
                
            elif key == Qt.Key_Space:
                # 空格不再触发补全，使窗口隐藏
                logger.info("空格键隐藏补全窗口")
                self.popup.hide()
                return False
            
            elif (key >= Qt.Key_Space and key <= Qt.Key_AsciiTilde) or key == Qt.Key_Period:
                # 普通字符输入时，不拦截，但设置延迟更新补全
                logger.debug(f"输入普通字符: '{key_text}'，延迟更新补全")
                QTimer.singleShot(10, self.show_completions)
                return False
            
            # 任何其他按键都不捕获，让编辑器正常处理
                return False
        
        # 自动触发补全的快捷键
        if not self.popup.isVisible():
            # 点号自动触发补全
            if key == Qt.Key_Period:
                # 延迟触发补全，让文本先更新
                logger.info("点号触发补全")
                QTimer.singleShot(10, self.show_completions)
                return False
                
            # Ctrl+Space手动触发补全
            if key == Qt.Key_Space and event.modifiers() == Qt.ControlModifier:
                logger.info("Ctrl+Space手动触发补全")
                QTimer.singleShot(10, self.show_completions)
                return True
            
        return False

    def update_metadata(self):
        """更新数据库元数据"""
        # 防止频繁更新
        current_time = time.time()
        if current_time - self.last_update_time < 30:  # 至少30秒间隔
            return
            
        try:
            self.last_update_time = current_time
            db = get_db_engine()
            
            # 获取所有表及其信息
            tables = db.get_loaded_tables()
            
            # 保存旧的表列信息，用于检测变化
            old_table_count = len(self.table_columns)
            old_column_count = sum(len(cols) for cols in self.table_columns.values())
            
            # 清空旧的表和列缓存
            self.table_columns = {}
            self.column_type_mappings = {}
            
            # 更新表架构信息
            for table_info in tables:
                table_name = table_info['table_name']
                schema = db.get_table_schema(table_name)
                
                # 记录表的列
                columns = []
                for col_info in schema:
                    col_name = col_info['name']
                    col_type = col_info['type']
                    columns.append(col_name)
                    
                    # 记录列的数据类型
                    self.column_type_mappings[f"{table_name}.{col_name}"] = col_type
                
                # 如果表没有列，加载示例数据
                if not columns and 'row_count' in table_info and table_info['row_count'] > 0:
                    try:
                        # 使用LIMIT 1获取一行数据来推断列
                        sample_data = db.execute_query(f"SELECT * FROM {table_name} LIMIT 1")
                        if sample_data and 'columns' in sample_data:
                            columns = [col['name'] for col in sample_data['columns']]
                            
                            # 推断数据类型
                            for col in sample_data['columns']:
                                col_name = col['name']
                                col_type = col.get('type', 'UNKNOWN')
                                self.column_type_mappings[f"{table_name}.{col_name}"] = col_type
                    except Exception as e:
                        logger.debug(f"通过示例数据获取列信息失败: {str(e)}")
                
                self.table_columns[table_name] = columns
            
            # 检测和记录元数据变化
            new_table_count = len(self.table_columns)
            new_column_count = sum(len(cols) for cols in self.table_columns.values())
            
            # 如果表数量或列数量有变化，记录日志
            if new_table_count != old_table_count or new_column_count != old_column_count:
                logger.info(f"数据库元数据已更新: {new_table_count}个表 (+{new_table_count - old_table_count}), "
                           f"{new_column_count}个列 (+{new_column_count - old_column_count})")
            else:
                logger.debug(f"已刷新数据库元数据: {new_table_count}个表, {new_column_count}个列")
                
            # 缓存视图和常用查询的元数据
            try:
                # 检查是否有视图表
                views_result = db.execute_query("SELECT name FROM sqlite_master WHERE type='view'")
                if views_result and 'data' in views_result and views_result['data']:
                    for row in views_result['data']:
                        view_name = row[0]
                        # 获取视图的列信息
                        view_schema = db.execute_query(f"SELECT * FROM {view_name} LIMIT 0")
                        if view_schema and 'columns' in view_schema:
                            columns = [col['name'] for col in view_schema['columns']]
                            self.table_columns[view_name] = columns
                            
                            # 记录列类型信息
                            for col in view_schema['columns']:
                                col_name = col['name']
                                col_type = col.get('type', 'UNKNOWN')
                                self.column_type_mappings[f"{view_name}.{col_name}"] = col_type
            except Exception as e:
                logger.debug(f"缓存视图元数据失败: {str(e)}")
                
            # 清理不再使用的别名
            self._clean_aliases()
                
        except Exception as e:
            logger.error(f"更新元数据时出错: {str(e)}")
            
    def _clean_aliases(self):
        """清理不再有效的别名"""
        # 找出无效的别名（指向不存在的表）
        invalid_aliases = []
        for alias, table in self.table_aliases.items():
            if not table.startswith("subquery_") and table not in self.table_columns:
                invalid_aliases.append(alias)
                
        # 删除无效的别名
        for alias in invalid_aliases:
            if alias in self.table_aliases:
                del self.table_aliases[alias]

    def _is_in_string_literal(self, text: str, position: int) -> bool:
        """检测光标是否在字符串字面量内
        
        Args:
            text: 要检查的文本
            position: 光标位置
            
        Returns:
            是否在字符串内部
        """
        # 计算到光标为止的引号数量
        single_quotes = text[:position].count("'") - text[:position].count("\\'")
        double_quotes = text[:position].count('"') - text[:position].count('\\"')
        backticks = text[:position].count('`') - text[:position].count('\\`')
        
        # 奇数个引号表示光标在引号内部
        return (single_quotes % 2 == 1) or (double_quotes % 2 == 1) or (backticks % 2 == 1)
    
    def _get_string_context(self, text: str, position: int) -> str:
        """获取字符串字面量的上下文
        
        如果光标在字符串内部，返回字符串内容，否则返回空字符串
        
        Args:
            text: 要检查的文本
            position: 光标位置
            
        Returns:
            字符串上下文
        """
        if not self._is_in_string_literal(text, position):
            return ""
            
        # 找到最近的未转义引号
        quote_chars = ["'", '"', '`']
        last_quote_pos = -1
        quote_char = None
        
        for char in quote_chars:
            # 向前查找最后一个引号
            pos = position - 1
            while pos >= 0:
                if text[pos] == char and (pos == 0 or text[pos-1] != '\\'):
                    if pos > last_quote_pos:
                        last_quote_pos = pos
                        quote_char = char
                    break
                pos -= 1
                
        if last_quote_pos == -1 or not quote_char:
            return ""
            
        # 提取字符串内容
        start = last_quote_pos + 1
        string_content = text[start:position]
        
        return string_content

    def eventFilter(self, obj, event):
        """事件过滤器，处理对象的各种事件
        
        Args:
            obj: 事件对象
            event: 事件
            
        Returns:
            是否已处理事件
        """
        # 如果是编辑器的事件
        if obj == self.editor:
            # 处理鼠标移动事件 (事件类型 25)
            if event.type() == 25 and self.popup and self.popup.isVisible():
                # 如果鼠标移出补全框区域，可以选择隐藏补全框
                # 这里不做处理，避免干扰用户操作
                pass
                
            # 处理鼠标按下事件 (事件类型 2)
            elif event.type() == 2 and self.popup and self.popup.isVisible():
                self.popup.hide()
                
        return False  # 让事件继续传递
